package com.mindata.blockmanager.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import sun.misc.BASE64Decoder;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

/**
 * The Class HttpTools.
 *
 * @author jonnyLee
 */
public class HttpTools {

    private static final Logger LOGGER = LoggerFactory.getLogger(HttpTools.class);

    private static Map<Long, Long> internalIpRange = new HashMap<Long, Long>();
    private static Map<Long, Long> trustedIpRange = new HashMap<Long, Long>();
    
    private HttpTools() {
    }

    /**
     * Host to long.
     *
     * @param ipAddress the ip address
     * @return the long
     */
    private static long hostToLong(String ipAddress) {
        long[] ip = new long[4];

        int position1 = ipAddress.indexOf(".");
        int position2 = ipAddress.indexOf(".", position1 + 1);
        int position3 = ipAddress.indexOf(".", position2 + 1);

        ip[0] = Long.parseLong(ipAddress.substring(0, position1));
        ip[1] = Long.parseLong(ipAddress.substring(position1 + 1, position2));
        ip[2] = Long.parseLong(ipAddress.substring(position2 + 1, position3));
        ip[3] = Long.parseLong(ipAddress.substring(position3 + 1));

        return (ip[0] << 24) + (ip[1] << 16) + (ip[2] << 8) + ip[3];
    }
    
    public static boolean isTrustedIp(String ip) {
        if (!isValidIp(ip)) {
            return false;
        }
        long currentIp = hostToLong(ip);
        
        Iterator<Entry<Long, Long>> it = trustedIpRange.entrySet().iterator();
        while (it.hasNext()) {
            Entry<Long, Long> entry = it.next();
            if (entry.getKey() <= currentIp && currentIp <= entry.getValue()) {
                return true;
            }
        }
        
        return false;
    }

    /**
     * Checks if is internal ip.
     *
     * @param ip the ip
     * @return true, if is internal ip
     */
    public static boolean isInternalIp(String ip) {
        if (!isValidIp(ip)) {
            return false;
        }
        long currentIp = hostToLong(ip);
        
        Iterator<Entry<Long, Long>> it = internalIpRange.entrySet().iterator();
        while (it.hasNext()) {
            Entry<Long, Long> entry = it.next();
            if (entry.getKey() <= currentIp && currentIp <= entry.getValue()) {
                return true;
            }
        }
        
        return false;
    }
    
    public static boolean isValidIp(String ip) {
        if (StringUtils.isEmpty(ip)) {
            return false;
        }
        
        if (ip.matches("(\\d{1,3}\\.){3}\\d{1,3}")) {
            return true;
        }
        
        return false;
    }

    /**
     * Gets the http client ip.
     *
     * @param request the request
     * @return the http client ip
     */
    public static String getHttpClientIP(HttpServletRequest request) {
        String ip = getHttpClientIPs(request);
        
        if (StringUtils.hasText(ip)) {
            ip = ip.split(",")[0].trim();
        }
        
        return ip;
    }

    /**
     * Gets the http client i ps.
     *
     * @param request the request
     * @return the http client i ps
     */
    public static String getHttpClientIPs(HttpServletRequest request) {
        String ip = "EMPTY";

        if (request.getHeaders("X-Forwarded-For").hasMoreElements()) {
            ip = request.getHeaders("X-Forwarded-For").nextElement();
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)|| "EMPTY".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)|| "EMPTY".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)|| "EMPTY".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)|| "EMPTY".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip) || "EMPTY".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        
        return ip.trim();
    }

    /**
     * 判断请求是否为ajax
     * @param request
     * @return
     */
    public static boolean isAjax(HttpServletRequest request) {
        return !StringUtils.isEmpty(request.getHeader("x-requested-with"));
    }

    /**
     * 获取网站地址
     * @param request
     * @return
     */
    public static String getContextPath(HttpServletRequest request) {
        return request.getScheme()+"://"+request.getServerName()+":"+ request.getServerPort() +request.getContextPath();
    }

    /**
     * 获取基本认证信息
     * @param request
     * @return
     */
    public static BasicAuthentication basicAuthentication(HttpServletRequest request) {
        //获取到的内容是结果base64编码后的字符串，所以这样的认证方式安全性不高 获取到的请求头格式类似于 Basic MTIzOjEyMw==
        String authValue = request.getHeader("Authorization");
        if(authValue != null){
            BASE64Decoder decoder = new BASE64Decoder();
            //通过解析后的用户名和密码格式例如 123:123
            String[] values;
            try {
                values = new String(decoder.decodeBuffer(authValue.split(" ")[1])).split(":");
            } catch (IOException e) {
                LOGGER.error("basic authentication decode error, authValue="+authValue, e);
                return null;
            }
            if(values.length == 2){
                return new BasicAuthentication(values[0], values[1]);
            }
        }
        return null;
    }

    /**
     * 基本认证信息
     */
    public static class BasicAuthentication {
        private String username;

        private String password;

        public BasicAuthentication(String username, String password) {
            this.username = username;
            this.password = password;
        }


        public String getUsername() {
            return username;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }
    }

    /**
     * 从限流参数中获取HttpServletRequest参数
     * @param objects 限流参数数组
     * @return HttpServletRequest
     */
    public static HttpServletRequest resolveHttpServletRequest(Object... objects){
        HttpServletRequest request = null;
        if (objects != null) {
            int len = objects.length;
            for(int i = 0; i < len; i++) {
                if (objects[i] instanceof HttpServletRequest) {
                    request = (HttpServletRequest)objects[i];
                    break;
                }
            }
        }
        return request;
    }
}
